#include <stdlib.h>
#include <string.h>

#include "mcl/mcl.h"
#include "mcl/args.h"

typedef struct{
   int hasargs;
   int which;
} mcl_args___flaginfo;

mcl_args_c mcl_args___nomemory;
mcl_args___args mcl_args___fi;

mcl_args_c* mcl_args_init( const char *name, 
                           const char *version, 
                           const char *summary, 
                           const char *details){
   mcl_args_c *context;
   
   if(!(context=(mcl_args_c *) malloc(sizeof(mcl_args_c)))){
      mcl_args___nomemory.status=MCL_STATUS_EMEM;
      return &mcl_args___nomemory;
   }
   *context=mcl_args___nomemory; // assigning default values;
   context->status=MCL_STATUS_OK;
   context->name=name;
   context->version=version;
   context->summary=summary;
   context->details=(details?details:NULL);
   
   return context;
}

int mcl_args_add_defaults(mcl_args_c *context){
   int status=0;
   status|=mcl_args_add(context, "help", 'h', "Display this help message."); 
   status|=mcl_args_add(context, "version", 'v', "Display this program's version.");
   return status;
}

int mcl_args_add( mcl_args_c *context, 
                  const char *longname, 
                  char shortname, 
                  const char *discription){
   if (!(context->list = (mcl_args___args *) realloc(context->list, sizeof(mcl_args___args)*(context->count+1)))){
      return MCL_STATUS_EMEM;
   }
   context->list[context->count].no=0;
   context->list[context->count].start=0;
   context->list[context->count].lf=longname;
   context->list[context->count].sf=shortname;
   context->list[context->count].disc=discription;
   context->count++;
   return MCL_STATUS_OK;
}

int mcl_args___mmatcher(mcl_args_c *c, const char *mflags){
   int length=strlen(mflags);
   int fcount=c->count;
   int i,j;
   
   for (i=0; i<length; ++i){
      for (j=0;j<fcount;++j){
         if (mflags[i]==c->list[j].sf){
            if(c->list[j].no) return MCL_STATUS_EPARSE;
            ++c->list[j].no;
            c->openflag=j;
            break;
         }
      }
      if (j==fcount) return MCL_STATUS_EPARSE;
   }
   return MCL_STATUS_OK;
}
int mcl_args___openlong(mcl_args_c *c, const char *flag){
   int fcount=c->count;
   int j;

   for (j=0;j<fcount;++j){
      if (!strcmp(flag, c->list[j].lf)){
         ++c->list[j].no;
         c->openflag=j;
         break;
      }
   }
   if (j==fcount) return MCL_STATUS_EPARSE;
   else return MCL_STATUS_OK;
}


int mcl_args_parse(mcl_args_c *c, int argc, char **argv){
   int i, foundaflag=0;
   for(i=0;i<argc;++i){
      if(argv[i][0]=='-' && argv[i][1]!='\0'){
         if(argv[i][1]=='-' && argv[i][2]!='\0'){ // long flags
            if(mcl_args___openlong(c, argv[i]+2)) return MCL_STATUS_EPARSE;
         }
         else{ // short flags
            if(mcl_args___mmatcher(c, argv[i]+1)) return MCL_STATUS_EPARSE;
         }
         foundaflag=1;
      }
      else{ // not a flag
         if (c->openflag){
            if(!c->list[c->openflag].start) c->list[c->openflag].start=i-1;
            ++c->list[c->openflag].no;
         }
         else{
            if(!foundaflag) c->before=i;
         }
      }
   }
   c->openflag=0;
   
   return MCL_STATUS_OK;
}

int mcl_args___find(mcl_args_c *c, const char *longflag){
   int i;
   for (i=0; i<c->count; ++i) if (!strcmp(longflag, c->list[i].lf)) return i;
   return -1;
}
int mcl_args_get_count(mcl_args_c *c, const char *longflag){
   int i = mcl_args___find(c, longflag);
   return c->list[i].no;
}
int mcl_args_get_start(mcl_args_c *c, const char *longflag){
   int i = mcl_args___find(c, longflag);
   return c->list[i].start;
}
int mcl_args_get_before(mcl_args_c *c){
   return c->before;
}

int mcl_args_exec_defaults(mcl_args_c *c){
   //TODO find help
}


mcl_args_c* mcl_args_fin(mcl_args_c *context){
   int i;
   if (!context) return NULL;
   free(context->list);
   free(context);
   return NULL;
}

/*
#include <stdio.h>
void print_all(mcl_args_c *c){
   int i;
   fputs(
"********************************************************************************", stderr
   );
   if(!c) {
      fprintf(stderr, "context is NULL.\n");
      return;
   }   
   
   for (i=0; i<c->count;++i){
      fprintf( stderr, 
      "Flag number %d:\n"
      "\tshort name: %c\n"
      "\tlong name: %s\n"
      "\tdiscription: \n\t\t%s\n"
      "\tstarting position of first argument: %d\n"
      "\tnumber of arguments: %d\n\n",
      i, c->list[i].sf, c->list[i].lf, c->list[i].disc, c->list[i].start, c->list[i].no
      );
   }
   fprintf( stderr, 
            "general information:\n"
            "program name: %s || version: %s || summary: %s || details: %s || before: %d || status: %d\n",
            c->name, c->version, c->summary, c->details, c->before, 
            c->status
   );
   fprintf(stderr, "total flags regestered: %d\n", c->count);
   fputs(
"********************************************************************************", stderr
   );
}*/
